// Originally from http://www.webtoolkit.info/javascript-trim.html
// Modified by me (09-16-2009)
String.prototype.trim = function(chars) {
	return this.rtrim(chars).ltrim(chars);
}
String.prototype.ltrim = function(chars) {
	chars = chars || "\\s";
	return this.replace(new RegExp("^[" + chars + "]+", "g"), "");
}
String.prototype.rtrim = function(chars) {
	chars = chars || "\\s";
	return this.replace(new RegExp("[" + chars + "]+$", "g"), "");
}

// From https://developer.mozilla.org/en/Debugging_a_XULRunner_Application
function dump(str) {
	Components.classes['@mozilla.org/consoleservice;1']
			  .getService(Components.interfaces.nsIConsoleService)
			  .logStringMessage(str);
}


var schedule_page_URL = "http://sis.rpi.edu/stuclshr.htm";

// Preferences interface
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
	getService(Components.interfaces.nsIPrefBranch);

// Storage interface
var directory = Components.classes["@mozilla.org/file/directory_service;1"]
	.getService(Components.interfaces.nsIProperties)
	.get("CurProcD", Components.interfaces.nsIFile);
directory.append("storage.sqlite");
var storageService = Components.classes["@mozilla.org/storage/service;1"]
	.getService(Components.interfaces.mozIStorageService);
var db_connection = storageService.openDatabase(directory);

function initialize() {
	return; // DEBUG

	// Create semesters table
	if (!db_connection.tableExists("semesters")) {
		var statement = "CREATE TABLE IF NOT EXISTS semesters ( id INTERGER PRIMARY KEY AUTOINCREMENT , ";
		statement += "name CHAR(100) , url CHAR(100) );";
		//alert(statement);
		db_connection.executeSimpleSQL(statement);
	}

	// Create courses table
	if (!db_connection.tableExists("courses")) {
		var statement = "CREATE TABLE IF NOT EXISTS courses ( id INTERGER PRIMARY KEY AUTOINCREMENT , ";
		statement += "deptartment CHAR(4) , class_number INT() , title CHAR(24) , url CHAR(100) );";
		//alert(statement);
		db_connection.executeSimpleSQL(statement);
	}

	// Create sections table
	if (!db_connection.tableExists("sections")) {
		var statement = "CREATE TABLE IF NOT EXISTS sections ( id INTERGER PRIMARY KEY AUTOINCREMENT , ";
		statement += "CRN INT , class_number INT() , title CHAR(24) , url CHAR(100) );";
		//alert(statement);
		db_connection.executeSimpleSQL(statement);
	}

	// Create meetings table
	if (!db_connection.tableExists("meetings")) {
		var statement = "CREATE TABLE IF NOT EXISTS meetings ( id INTERGER PRIMARY KEY AUTOINCREMENT , ";
		statement += "CRN INT , class_number INT() , title CHAR(24) , url CHAR(100) );";
		//alert(statement);
		db_connection.executeSimpleSQL(statement);
	}
}

function downloadNewSchedules() {
	document.getElementById("status").label = "Downloading list of semesters . . .";

	// Request a web page
    var http = new XMLHttpRequest();
    http.open("GET", schedule_page_URL, true); // The page that lists the schedule files
	http.overrideMimeType("text/xml");
	http.onreadystatechange = function() {
		if (http.status != "200") { // HTTP response was not "OK" (200)
			alert("There was an error. File could not be retrieved.");
			close();
		}
	}
	http.send(null);
	http.onload = function() { // File successfully loaded
		var term_selector = document.getElementById("term-selector");
		term_selector.removeAllItems(); // Clear "old" schedules
		var regex = /<a href="([^"]+?\.txt)">(.+?)<\/a>/gi; // Find all links on page
		var results;
		while ((results = regex.exec(http.responseText)) != null) {
			// Add schedules
			term_selector.appendItem(results[2], schedule_page_URL.substring(0, schedule_page_URL.lastIndexOf("/")) + results[1]);
		}
		document.getElementById("status").label = "Done.";
	}
}

function loadSchedule() {
	var term_selector_current_value = document.getElementById("term-selector").value;
	var raw_scheduler_browser = document.getElementById("raw-scheduler-browser");
	
	document.getElementById("status").label = "Downloading semester file . . .";
	
	// Request a web page
    var http = new XMLHttpRequest();
    http.open("GET", term_selector_current_value, true); // The page that lists the schedule files
	http.overrideMimeType("text/xml");
	http.onreadystatechange = function() {
		if (http.status != "200") { // HTTP response was not "OK" (200)
			alert("There was an error. File could not be retrieved.");
			close();
		}
	}
	http.send(null);
	http.onload = function() { // File successfully loaded
		// Set browser content to schedule file
		raw_scheduler_browser.loadURI(term_selector_current_value, null, null);
		document.getElementById("status").label = "Done.";
		parse(http.responseText);
	}
}

/*const boost::regex class_pattern("(?:(?:  \\d{5} ([A-Z]{4}-\\d{4})[^\\r\\n]+[\\r\\n])(?: {47}[^\\r\\n]+[\\r\\n])*(?: {10}NOTE: [^\\r\\n]+[\\r\\n])*[\\r\\n])(?:(?:  \\d{5} \\1[^\\r\\n]+[\\r\\n])(?: {47}[^\\r\\n]+[\\r\\n])*(?: {10}NOTE: [^\\r\\n]+[\\r\\n])*[\\r\\n])*");
const boost::regex section_pattern("(?:  \\d{5} [A-Z]{4}-\\d{4}[^\\r\\n]+[\\r\\n])(?: {47}[^\\r\\n]+[\\r\\n])*(?: {10}NOTE: [^\\r\\n]+[\\r\\n])*[\\r\\n]");
const boost::regex class_data_pattern("  (?:(?:(\\d{5}) ([A-Z]{4})-(\\d{4})-([\\dA-Z]{2}) (.{1,25})| {44}) ([A-Z ]{3}) ([\\d -]{1,4}) ([A-Z ]{2}) ([MTWRFS ]{6}) (?:([\\d ]{2}:[\\d ]{2}) ([\\d ]{2}:\\d{2}[AP]M)|(\\*{2} TBA \\*{2}) {4}) (.{1,21})(?:  (.{1,17}))?(?: ([\\d ]{1,3})  ([\\d ]{1,3})  ([\\d -]{1,3}))?| {8}NOTE: (.+))[\\r\\n]");
const boost::regex clean_page_header_pattern("[\\xc^][\\s]+[^\\r\\n]+[\\r\\n][\\s]+[^\\r\\n]+[\\r\\n][\\s]+[^\\r\\n]+[\\r\\n]{2}[\\s]+CLS[^\\r\\n]+[\\r\\n]  CRN[^\\r\\n]+[\\r\\n][ -]+[\\r\\n]");
const boost::regex clean_department_header_pattern("[\\r\\n]  [A-Z]{4}[\\r\\n]  -+[\\r\\n]{2}");*/
function parse(str) {
	var lines = str.split(/[\r\n]/);
	var total = lines.length;
	var course_id = "";
	
	document.getElementById("status").label = "Parsing semester file . . .";

	for (i in lines) {
		var course = undefined;
		var section = undefined;
		var meeting = undefined;
		var note = undefined;

		//dump(i);
		//var line = lines[i].trim();
		var line = lines[i];
		if (line.match(/^  \d{5}/)) { // Course
			//alert(i + " Course: " + line);
			course = {
				"dept" : line.substr(8,4), // Department
				"number" : line.substr(13,4), // Course #
				"title" : line.substr(21,24).rtrim(), // Title
				"grade type" : line.substr(56,2).rtrim() // Grade Type
			};
			section = {
				"crn" : line.substr(2,5), // CRN #
				"number" : line.substr(18,2), // Section #
				"credit hours" : line.substr(51,4).rtrim(),
				"max credit hours" : 0,
				"max enrolled" : parseInt(line.substr(121,4).rtrim()),
				"enrolled" : parseInt(line.substr(126,4).rtrim()),
				"seats remaining" : parseInt(line.substr(131,4).rtrim())		
			}
			meeting = {
				"class type" : line.substr(47,3).rtrim(),
				"class days" : line.substr(59,5), // Don't trim this, we're gonna use position later
				"start time" : line.substr(66,5).ltrim(),
				"end time" : line.substr(72,7).ltrim(),
				"instructor" : line.substr(80,21).rtrim(),
				"location" : line.substr(103,17).rtrim()
			}
		} else if (line.match(/^ {47}[A-Z].{20}\d/)) { // Meeting
			meeting = {
				"class type" : line.substr(47,3).rtrim(),
				"class days" : line.substr(59,5), // Don't trim this, we're gonna use position later
				"start time" : line.substr(66,5).ltrim(),
				"end time" : line.substr(72,7).ltrim(),
				"instructor" : line.substr(80,21).rtrim(),
				"location" : line.substr(103,17).rtrim()
			}
		} else if (line.match(/^ {10}NOTE:/)) { // Note
			note = line.substr(17);
		}
		
		if (course && (course["dept"] + "-" + course["number"]) != course_id) {
			// SQL Stuff here
		}
		if (course) {
			//alert("Course: " + JSON.stringify(course));
		}
		if (section) {
			if (typeof(section["credit hours"]) != "number" && section["credit hours"].indexOf("-") != -1) {
				var temp = section["credit hours"].split("-");
				section["credit hours"] = parseInt(temp[0]);
				section["credit hours"] = parseInt(temp[1]);
			} else {
				section["credit hours"] = parseInt(section["credit hours"]);
			}
			// SQL Stuff here
			//alert("Section: " + JSON.stringify(section));
		}
		if (meeting) {
			// Handle class days
			var temp = meeting["class days"]; // 000M TWRF
			//dump(temp);
			//dump(typeof(temp));
			meeting["class days"] = 0;
			if (temp.charAt(0) == "M") {
				meeting["class days"] += 16; // 0001 0000
			}
			if (temp.charAt(0) == "T") {
				meeting["class days"] += 8; // 0000 1000
			}
			if (temp.charAt(0) == "W") {
				meeting["class days"] += 4; // 0000 0100
			}
			if (temp.charAt(0) == "R") {
				meeting["class days"] += 2; // 0000 0010
			}
			if (temp.charAt(0) == "F") {
				meeting["class days"] += 1; // 0000 0001
			}

			if (meeting["start time"] == "** TB") {
				meeting["start time"] = meeting["end time"] = "";
			} else {
				var start = meeting["start time"].split(":"); // Split into hours and minutes
				var end = meeting["end time"].split(":"); // Split into hours and minutes
				var ampm = end[1].substr(2); // AM or PM

				var start_hr = parseInt(start[0]); // Start time in military time
				if (ampm == "PM" && start_hr < 10) {
					// If PM and starting before 10:00 then consider it an afternoon time
					// This eliminates a class that starts at 11:00 AM and ends at 1:50 PM
					start_hr += 12;
				}

				var end_hr = parseInt(end[0]) + (ampm == "PM") * 12; // End hour in military time

				meeting["start time"] = (start_hr - 6) * 60 + parseInt(start[1]); // Time in minutes since 6:00 AM
				meeting["end time"] = (end_hr - 6) * 60 + parseInt(end[1].substr(0,2)); // Time in minutes since 6:00 AM
			}
			if (meeting["location"] == "* TBA *") {
				meeting["location"] = "";
			}
			// SQL Stuff here
			//alert("Meeting: " + JSON.stringify(meeting));
		}
		if (note) {
			// SQL Stuff here
			//alert("Note: " + JSON.stringify(note));
		}

		// Progress meter of parsing file
		document.getElementById("progress").value = i / total * 100;
		if (i > 30) {
			//break;
		}
	}

	document.getElementById("status").label = "Done.";
}
